package option

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"git.mycaigou.com/gfyx/common/cache"
	"git.mycaigou.com/gfyx/common/usermetadata"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/constants"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/base/area"
	orgRepo "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/base/org"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/base/profit"
	userRepo "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/base/user"
	bigdataRemote "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/remote/bigdata_remote"
	commonPb "git.mycaigou.com/gfyx/micro-gfyx-oppty-service/proto/micro_gfyx_oppty_service_proto/micro-gfyx-oppty-service/common"
	"git.myscrm.cn/golang/stark/v4"
)

type optionService struct {
	profitRepo         profit.ProfitRepositoryIface
	areaRepo           area.AreaConfigRepositoryIface
	bigDataServiceRepo bigdataRemote.BigDataServiceRepositoryIface
	userNewRepos       userRepo.UserRepositoryIface
	orgRepos           orgRepo.OrgRepositoryIface
}

func NewOptionService(
	profitRepo profit.ProfitRepositoryIface,
	areaRepo area.AreaConfigRepositoryIface,
	bigDataServiceRepo bigdataRemote.BigDataServiceRepositoryIface,
	userNewRepos userRepo.UserRepositoryIface,
	orgRepos orgRepo.OrgRepositoryIface,
) OptionServiceIface {
	return &optionService{
		profitRepo:         profitRepo,
		areaRepo:           areaRepo,
		bigDataServiceRepo: bigDataServiceRepo,
		userNewRepos:       userNewRepos,
		orgRepos:           orgRepos,
	}
}

func (s *optionService) GetRadarAreaOption(ctx context.Context) (*commonPb.GetRadarAreaOptionResponse, error) {
	profitList, err := s.profitRepo.QueryAllEffectiveProfitList(ctx)
	if err != nil {
		return nil, err
	}

	if len(profitList) == 0 {
		return nil, errors.New("租户权益已到期")
	}

	isNationWideProfit := false
	for _, profitPo := range profitList {
		if profitPo.ProfitCode == constants.ProfitClueRadarNationwide {
			isNationWideProfit = true
			break
		}
	}
	metaUserInfo := usermetadata.GetMetaUserInfo(ctx)
	if metaUserInfo.TenantUserUid == "" {
		return nil, errors.New("用户未登录")
	}
	userPo, err := s.userNewRepos.GetUserByCondition(ctx, map[string]interface{}{"uid": metaUserInfo.TenantUserUid})
	if err != nil {
		return nil, err
	}

	var buPermAreas []string
	if userPo.Id > 0 {
		// 获取用户所属区域
		userOrgList, err := s.orgRepos.GetOrgListByUserId(ctx, userPo.Id)
		if err != nil || len(userOrgList) == 0 {
			return nil, errors.New(fmt.Sprintf("id为 %d 的用户，没有所属组织", userPo.Id))
		}
		userOrgIds := make([]int64, 0)
		for _, userOrg := range userOrgList {
			userOrgIds = append(userOrgIds, userOrg.OrganizationId)
		}
		orgAreas, err := s.orgRepos.OrgAreaListByOrgIds(ctx, userOrgIds)
		if err != nil {
			return nil, errors.New("组织没有关联区域")
		}
		for _, orgArea := range orgAreas {
			buPermAreas = append(buPermAreas, orgArea.AreaCode)
		}
	}

	allArea, err := s.areaRepo.AreaConfigList(ctx)
	if err != nil {
		return nil, err
	}

	result := &commonPb.GetRadarAreaOptionResponse{}
	resultCodeSet := make(map[string]bool)
	// 找父级code
	code2AreaPo := make(map[string]*area.GfyxAreaConfigPo)
	parentCode2children := make(map[string][]*area.GfyxAreaConfigPo)
	for _, areaItem := range allArea {
		code2AreaPo[areaItem.ItemCode] = areaItem

		if children, ok := parentCode2children[areaItem.ParentCode]; ok {
			children = append(children, areaItem)
			parentCode2children[areaItem.ParentCode] = children
		} else {
			parentCode2children[areaItem.ParentCode] = []*area.GfyxAreaConfigPo{areaItem}
		}

	}

	if isNationWideProfit {
		//全国版的权益
		//如果用户所在bu有配置区域权限，那么取区域权限，否则，返回全国的省市
		if len(buPermAreas) == 0 {
			for _, areaItem := range allArea {
				result.Options = append(result.Options, &commonPb.AreaOption{
					AreaCode:   areaItem.ItemCode,
					Area:       areaItem.ItemName,
					ParentCode: areaItem.ParentCode,
				})
			}
		} else {
			//如果用户有全国权限，那么返回全国的省市，否则，返回用户有权限的省市，省市需要补充旗下所有城市
			hasNationCode := false
			for _, permAreaCode := range buPermAreas {
				if permAreaCode == "0" {
					hasNationCode = true
				}
			}
			if hasNationCode {
				result.Options = []*commonPb.AreaOption{}
				for _, areaItem := range allArea {
					result.Options = append(result.Options, &commonPb.AreaOption{
						AreaCode:   areaItem.ItemCode,
						Area:       areaItem.ItemName,
						ParentCode: areaItem.ParentCode,
					})
				}
			} else {
				for _, permAreaCode := range buPermAreas {
					if _, ok1 := resultCodeSet[permAreaCode]; !ok1 {
						if areaPo, ok2 := code2AreaPo[permAreaCode]; ok2 {
							result.Options = append(result.Options, &commonPb.AreaOption{
								AreaCode:   areaPo.ItemCode,
								Area:       areaPo.ItemName,
								ParentCode: areaPo.ParentCode,
							})
							resultCodeSet[permAreaCode] = true

							//如果是省份，则把省下的所有城市都加到结果集中
							if areaPo.ParentCode == "0" {
								if children, ok := parentCode2children[areaPo.ItemCode]; ok {
									for _, childArea := range children {
										result.Options = append(result.Options, &commonPb.AreaOption{
											AreaCode:   childArea.ItemCode,
											Area:       childArea.ItemName,
											ParentCode: childArea.ParentCode,
										})
										resultCodeSet[childArea.ItemCode] = true
									}
								}
							}
						}
					}
				}
			}
		}
	} else {
		//省份版的权益
		// 先获取权益省份
		profitProvincePos, err := s.profitRepo.QueryProfitProvinceList(ctx)
		if err != nil {
			return nil, err
		}
		profitProvinceCodeSet := make(map[string]bool)
		for _, profitProvincePo := range profitProvincePos {
			profitProvinceCodeSet[profitProvincePo.ProvinceCode] = true
		}

		//如果用户所在bu有配置区域权限，那么取省份权益和区域权限的交集，否则，返回所有省市数据
		if len(buPermAreas) == 0 {
			for _, profitProvincePo := range profitProvincePos {
				for _, areaItem := range allArea {
					// 省和市的数据都取
					if areaItem.ItemCode == profitProvincePo.ProvinceCode ||
						areaItem.ParentCode == profitProvincePo.ProvinceCode {
						result.Options = append(result.Options, &commonPb.AreaOption{
							AreaCode:   areaItem.ItemCode,
							Area:       areaItem.ItemName,
							ParentCode: areaItem.ParentCode,
						})
					}
				}
			}
		} else {
			var intersectionAreaCode []string //权益和权限的交集
			for _, permAreaCode := range buPermAreas {
				areaPo, ok := code2AreaPo[permAreaCode]
				if ok {
					if areaPo.ParentCode == "0" {
						//areaPo是省份
						if ok2 := profitProvinceCodeSet[areaPo.ItemCode]; ok2 {
							intersectionAreaCode = append(intersectionAreaCode, permAreaCode)
						}
					} else {
						//areaPo是城市
						if ok2 := profitProvinceCodeSet[areaPo.ParentCode]; ok2 {
							intersectionAreaCode = append(intersectionAreaCode, permAreaCode)
						}
					}
				}
			}

			for _, areaCode := range intersectionAreaCode {
				// 最后的结果集出重，避免省份和这个省其下城市同时存在时造成的数据重复
				if _, ok := resultCodeSet[areaCode]; !ok {
					if areaPo, ok2 := code2AreaPo[areaCode]; ok2 {
						result.Options = append(result.Options, &commonPb.AreaOption{
							AreaCode:   areaPo.ItemCode,
							Area:       areaPo.ItemName,
							ParentCode: areaPo.ParentCode,
						})
						resultCodeSet[areaCode] = true

						//如果是省份，则把省下的所有城市都加到结果集中
						if areaPo.ParentCode == "0" {
							if children, ok := parentCode2children[areaPo.ItemCode]; ok {
								for _, childArea := range children {
									result.Options = append(result.Options, &commonPb.AreaOption{
										AreaCode:   childArea.ItemCode,
										Area:       childArea.ItemName,
										ParentCode: childArea.ParentCode,
									})
									resultCodeSet[childArea.ItemCode] = true
								}
							}
						}
					}
				}
			}
		}
	}
	return result, nil
}

func (s *optionService) GetOption(ctx context.Context, request *commonPb.GetOptionRequest) (*commonPb.GetOptionResponse, error) {
	resp := &commonPb.GetOptionResponse{}

	for _, groupItem := range request.OptionGroup {
		switch groupItem {
		case constants.OptionGroupLandUsageLabel, constants.OptionGroupProjectNatureLabel,
			constants.OptionGroupProjectTypeLabel, constants.OptionGroupFitmentFeeLabel,
			constants.OptionGroupCompanyLevel, constants.OptionGroupCompanyLabel,
			constants.OptionGroupCompanyType, constants.OptionGroupCompanyIdentity,
			constants.OptionGroupPropertyCategory, constants.OptionGroupBidStage,
			constants.OptionGroupNoticeType, constants.OptionGroupBidType,
			constants.OptionGroupCreditLevel:
			resp.Options = append(resp.Options, s.getFilterOption(ctx, groupItem)...)
		case constants.OptionGroupAreaCode:
			resp.Options = append(resp.Options, s.getAllArea(ctx)...)
		case constants.OptionGroupIndustryCategory:
			resp.Options = append(resp.Options, s.getIndustryCategory(ctx)...)
		}
	}

	return resp, nil
}

func (s *optionService) getAllArea(ctx context.Context) (result []*commonPb.OptionItem) {
	allArea, err := s.areaRepo.AreaConfigList(ctx)
	if err != nil {
		return
	}

	for _, areaItem := range allArea {
		result = append(result, &commonPb.OptionItem{
			Text:        areaItem.ItemName,
			Value:       areaItem.ItemCode,
			ParentValue: areaItem.ParentCode,
			BelongGroup: constants.OptionGroupAreaCode,
		})
	}
	return
}

// 行业分类
func (s *optionService) getIndustryCategory(ctx context.Context) (result []*commonPb.OptionItem) {
	cacheRedis, _ := cache.TenantRedis()
	cacheKey := "option:industry_category"

	cacheResult, err := cacheRedis.Get(ctx, cacheKey)
	if err != nil {
		return
	}
	//优先取缓存，其次取数芯接口数据
	if cacheResult == "" || cacheResult == "null" {
		// 缓存失效
		data, err := s.bigDataServiceRepo.GetIndustryTag(ctx, &bigdataRemote.GetIndustryCategoryRequest{PageInfo: bigdataRemote.PageInfo{
			Page:     1,
			PageSize: 1000,
		}})
		if err != nil {
			return
		}
		// 一、二、三级分类code的map
		bigCategoryMap, middleCategoryMap, smallCategoryMap := make(map[string]*commonPb.OptionItem), make(map[string]*commonPb.OptionItem), make(map[string]*commonPb.OptionItem)

		if data != nil && len(data.List) > 0 {
			for _, item := range data.List {
				if _, exist := bigCategoryMap[item.IndustryCategoryBigCode]; !exist {
					newOptionItem := &commonPb.OptionItem{
						Text:        item.IndustryCategoryBig,
						Value:       item.IndustryCategoryBigCode,
						ParentValue: "",
						BelongGroup: constants.OptionGroupIndustryCategory,
					}
					bigCategoryMap[item.IndustryCategoryBigCode] = newOptionItem
					result = append(result, newOptionItem)
				}
				if _, exist := middleCategoryMap[item.IndustryCategoryMiddleCode]; !exist {
					newOptionItem := &commonPb.OptionItem{
						Text:        item.IndustryCategoryMiddle,
						Value:       item.IndustryCategoryMiddleCode,
						ParentValue: item.IndustryCategoryBigCode,
						BelongGroup: constants.OptionGroupIndustryCategory,
					}
					middleCategoryMap[item.IndustryCategoryMiddleCode] = newOptionItem
					result = append(result, newOptionItem)
				}
				if _, exist := smallCategoryMap[item.IndustryCategorySmallCode]; !exist {
					newOptionItem := &commonPb.OptionItem{
						Text:        item.IndustryCategorySmall,
						Value:       item.IndustryCategorySmallCode,
						ParentValue: item.IndustryCategoryMiddleCode,
						BelongGroup: constants.OptionGroupIndustryCategory,
					}
					smallCategoryMap[item.IndustryCategorySmallCode] = newOptionItem
					result = append(result, newOptionItem)
				}
			}
		}

		if len(result) > 0 {
			bytes, _ := json.Marshal(result)
			_, _ = cacheRedis.Set(ctx, cacheKey, string(bytes), true, 3600)
		}
	} else {
		// 缓存命中
		_ = json.Unmarshal([]byte(cacheResult), &result)
	}

	return
}

func (s *optionService) getFilterOption(ctx context.Context, filterType string) (result []*commonPb.OptionItem) {
	cacheRedis, _ := cache.TenantRedis()
	cacheKey := "option:" + filterType

	cacheResult, err := cacheRedis.Get(ctx, cacheKey)
	if err != nil {
		return
	}
	//优先取缓存，其次取数芯接口数据
	if cacheResult == "" || cacheResult == "null" {
		// 缓存失效
		data, err := s.bigDataServiceRepo.GetFilterList(ctx, &bigdataRemote.GetFilterListRequest{
			FilterType: filterType,
			Page:       1,
			PageSize:   1000,
		})
		if err != nil {
			return
		}

		if data != nil && len(data.List) > 0 {
			for _, item := range data.List {
				result = append(result, &commonPb.OptionItem{
					Text:        item.FilterText,
					Value:       item.FilterValue,
					ParentValue: item.ParentValue,
					BelongGroup: filterType,
				})
			}
		}

		if len(result) > 0 {
			bytes, _ := json.Marshal(result)
			_, _ = cacheRedis.Set(ctx, cacheKey, string(bytes), true, 7200)
		}
	} else {
		// 缓存命中
		_ = json.Unmarshal([]byte(cacheResult), &result)
	}
	return
}

func (s *optionService) GetInvestCompanyOption(ctx context.Context, request *commonPb.GetInvestCompanyOptionRequest) (*commonPb.GetInvestCompanyOptionResponse, error) {
	bigDataRequest := &bigdataRemote.GetInvestCompanyRequest{
		OrganizingCode: request.OrganizingCode,
		PageNum:        1,
		PageSize:       10000,
	}

	bigDataInvestCompanyResponse, err := s.bigDataServiceRepo.GetInvestCompany(ctx, bigDataRequest)
	if err != nil {
		stark.Logger.Error(ctx, "bigdata GetInvestCompany,err:%s", err.Error())
	}
	result := &commonPb.GetInvestCompanyOptionResponse{}
	if bigDataInvestCompanyResponse == nil {
		return result, nil
	}

	for _, item := range bigDataInvestCompanyResponse.List {
		data := &commonPb.InvestCompanyOptionItem{}
		data.Value = item.SubOrganizingCode
		data.Text = item.SubCompanyName
		data.Parent = item.SubParentOrganizingCode
		result.List = append(result.List, data)
	}
	return result, nil
}
